/********************************************************************
File:			ED1Scene.cpp
Purpose:		The defintion of the functions of our ED1Scene Class
Author:			Kent Ward [kward@fullsail.com]
School:			Full Sail University
Last Modified:	July 22nd, 2009
********************************************************************/

#include "ED1Scene.h"
#include <windows.h>
#include "glee.h"
#include <gl/gl.h>
#include <gl/glu.h>
#include "GOD.h"

#include "BMPFile.h"

#define NUM_AGENTS 15

extern HDC hDC;
extern int nFontList;


ED1Scene::~ED1Scene(void)
{
}

ED1Scene& ED1Scene::GetInstance()
{
	static ED1Scene theScene;
	return theScene;
}

void ED1Scene::InitializeScene(int iScreenWidth, int iScreenHeight, bool bFullScreen)
{
	m_iScreenWidth = iScreenWidth;
	m_iScreenHeight = iScreenHeight;
	m_bFullScreen = bFullScreen;

	GLfloat noLight[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
	GLfloat fullLight[4] = { 1.0f, 1.0f, 1.0f, 1.0f };

	//Some OpenGL state initialization
	glClearColor(0.1f, 0.1f, 0.5f, 1.0f);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glLightfv(GL_LIGHT0, GL_AMBIENT, noLight);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, fullLight);
	glLightfv(GL_LIGHT0, GL_SPECULAR, fullLight);
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, noLight);

	glEnable(GL_COLOR_MATERIAL);
	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, fullLight);
	glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 30);

	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	glLineStipple( 1, 0xAAAA );

	m_Timer.Reset();


	// initialize our agents.

	m_vAgents.resize(NUM_AGENTS);
	for (unsigned int i = 0; i < NUM_AGENTS; ++i)
	{
		//m_vAgents[i] = SGKAgent bob;
		vec3f vec((float)((rand() % 21) - 10), 0.2f, (float)((rand() % 21) - 10));
		m_vAgents[i].SetRadius(0.1f);
		m_vAgents[i].SetCenter(vec);
		m_vAgents[i].Init();
		m_vAgents[i].Own(&m_vAgents[i]);
	}

	// init font
	HFONT hFont;
	LOGFONT logfont;

	logfont.lfHeight = -10;
	logfont.lfWidth = 0;
	logfont.lfEscapement = 0;
	logfont.lfOrientation = 0;
	logfont.lfWeight = FW_THIN;
	logfont.lfItalic = FALSE;
	logfont.lfUnderline = FALSE;
	logfont.lfStrikeOut = FALSE;
	logfont.lfCharSet = ANSI_CHARSET;
	logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
	logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
	logfont.lfQuality = DEFAULT_QUALITY;
	logfont.lfPitchAndFamily = DEFAULT_PITCH;
	strcpy(logfont.lfFaceName, "Verdana");

	hFont = CreateFontIndirect(&logfont);
	SelectObject(hDC, hFont);

	nFontList = glGenLists(128);
	wglUseFontBitmaps(hDC, 0, 128, nFontList);

	DeleteObject(hFont);
	// wasn't that fun?  now it's time to extern hDC.

	m_Camera.LookAt(vec3f(0.f, 0.f, 0.f));

}

void ED1Scene::ResizeWindow(int iScreenWidth, int iScreenHeight)
{
	if(!iScreenHeight)
		iScreenHeight = 1;
	m_iScreenWidth = iScreenWidth;
	m_iScreenHeight = iScreenHeight;

	glViewport(0, 0, m_iScreenWidth, m_iScreenHeight);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(45, (float)iScreenWidth/(float)iScreenHeight, 0.1f, 300.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void ED1Scene::UpdateFrame()
{
	// Get the elapsed seconds since the last frame
	float fTimeElapsed = m_Timer.GetElapsedTime() * God::GetInstance()->GetTimeMod();
	m_Timer.Reset();


	for (unsigned int i = 0; i < m_vAgents.size(); ++i)
	{
		m_vAgents[i].Update(fTimeElapsed);
	}

	// Clear our screen
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Save the identity
	glPushMatrix();
		
		// Update our camera
		m_Camera.Update(fTimeElapsed);
		m_Camera.ApplyCameraTransform();

		char buffer[256];
		float ratio = God::GetInstance()->GetTimeMod();
		int agents = NUM_AGENTS;
		int pps = (0.96f / fTimeElapsed) * NUM_AGENTS;

		ZeroMemory(buffer, 256);
		sprintf(buffer, "All Systems Normal... \nTime Ratio: x%.3f \n Agents:%d \n Plans (A*) per second: %d \0", ratio, agents, pps);
		m_Camera.debugText(buffer);

		// Set LIGHT0's position
		float fPos[4] = { 0.0f, 6.0f, 0.0f, 1.0f };
		glLightfv( GL_LIGHT0, GL_POSITION, fPos );

		//Draw the ground unlit
		glColor3f(0.0f, 0.25f, 0.0f);
		glDisable(GL_LIGHTING);
		DrawGround();
		
		// Draw the world's coordinate axes
		DrawAxes();

		m_Frustum.Render();
		glEnable( GL_LIGHTING );

		for (unsigned int i = 0; i < m_vAgents.size(); ++i)
		{
			m_vAgents[i].Draw();
		}

		God::GetInstance()->DrawObjects();

	glPopMatrix();
}

void ED1Scene::Shutdown()
{
	//Delete Dynamic Memory here
	for (unsigned int i = 0; i < NUM_AGENTS; ++i)
	{
		m_vAgents[i].Kill();
	}
}


void ED1Scene::DrawGround(void)
{
	GLfloat halfSize = 20.0f;
	GLfloat stepSize = 0.5f;
	GLfloat groundLevel = 0.0f;

	glBegin(GL_LINES);
	for(GLfloat x = -halfSize; x <= halfSize; x+= stepSize)
	{
		// These lines horizontal
		glVertex3f(-halfSize, groundLevel, x);
		glVertex3f(halfSize, groundLevel, x);
		// These lines vertical
		glVertex3f(x, groundLevel, -halfSize);
		glVertex3f(x, groundLevel, halfSize);
	}
	glEnd();

}

void ED1Scene::DrawAxes(float fScale)
{
	glDisable( GL_DEPTH_TEST );
	glBegin(GL_LINES);
		glColor3f( 1.0f, 0.0f, 0.0f );
		glVertex3f( 0.0f, 0.0f, 0.0f );
		glVertex3f( fScale, 0.0f, 0.0f );

		glColor3f( 0.0f, 1.0f, 0.0f );
		glVertex3f( 0.0f, 0.0f, 0.0f );
		glVertex3f( 0.0f, fScale, 0.0f );

		glColor3f( 0.0f, 0.0f, 1.0f );
		glVertex3f( 0.0f, 0.0f, 0.0f );
		glVertex3f( 0.0f, 0.0f, -fScale );
	glEnd();
	glEnable( GL_DEPTH_TEST );
}
